package com.song.util;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

@Data
@Slf4j
@Component
@ConfigurationProperties(prefix = "ftp")
public class FtpUtil {
    private String host = "localhost";
    private Integer port = 2121;
    private String username;
    private String password;
    private String path;
    private int timeout = 30000;

    //连接ftp服务器
    public FTPClient connectFtp(){
        FTPClient ftpClient = null;
        try {
            ftpClient = new FTPClient();
            ftpClient.connect(host, port);
            ftpClient.login(username, password);
            ftpClient.setConnectTimeout(timeout);
            ftpClient.setControlEncoding("UTF-8");
            //设置文件为二进制传输，可以保证传输内容不被修改
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())){
                log.info("FTP连接失败，用户名或密码错误");
                closeFtp(ftpClient);
            }else {
                log.info("FTP连接成功");
            }
        }catch (Exception e){
            log.info("FTP连接失败，请检查配置是否正确：" + e);
        }
        return ftpClient;
    }

    //关闭ftp连接
    public void closeFtp(FTPClient ftpClient){
        if (ftpClient.isConnected()){
            try {
                ftpClient.disconnect();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    //上传
    public boolean upload(InputStream is, String remote, String filename){
        boolean flag = false;
        FTPClient ftpClient = connectFtp();
        if (ftpClient == null){
            return flag;
        }
        try {
            createDirectory(ftpClient, remote);
            boolean storeFlag = ftpClient.storeFile(filename, is);
            if (storeFlag){
                log.info(String.format("上传文件【%s】至目录【%s】成功！", filename, remote));
                flag = true;
            }else {
                log.info(String.format("上传文件【%s】至目录【%s】失败！", filename, remote));
            }
        } catch (IOException e) {
            log.error(String.format("上传文件【%s】至目录【%s】失败！", filename, remote));
        }finally {
            closeFtp(ftpClient);
        }
        return flag;
    }

    public void download(FTPClient ftpClient, String remote, String filename, String downloadPath){
        InputStream is = null;
        OutputStream os = null;
        File targetFile = new File(downloadPath + File.separator + filename);
        try {
            is = ftpClient.retrieveFileStream(remote + File.separator + filename);
            if (!targetFile.getParentFile().exists()){
                targetFile.getParentFile().mkdirs();
            }
            os = new FileOutputStream(targetFile);
            //读取方式一
            int length;
            byte[] bytes = new byte[1024];
            while ((length = is.read(bytes)) != -1){
                os.write(bytes, 0, length);
            }
            //读取方式二
//            ftpClient.retrieveFile(filename, os);
            ftpClient.completePendingCommand();
            log.info(String.format("从【%s】下载文件【%s】至【%s】成功", remote, filename, downloadPath));
        } catch (IOException e) {
            log.error("下载文件失败" + e);
        }finally {
            try {
                if (os != null){
                    os.close();
                }
                if (is != null){
                    is.close();
                }
            }catch (IOException e){
                log.error("下载流关闭失败" + e);
            }
            closeFtp(ftpClient);
        }
    }

    //切换工作目录
    private boolean changeWorkingDirectory(FTPClient ftpClient, String directory){
        boolean changeFlag = true;
        try {
            changeFlag = ftpClient.changeWorkingDirectory(directory);
            if (changeFlag){
                log.info("进入目录【" + directory + "】成功！");
            }else {
                log.info("进入目录【" + directory + "】失败，开始创建目录！");
            }
        } catch (IOException e) {
            log.error("进入目录【" + directory + "】失败!" + e);
        }
        return changeFlag;
    }

    //创建多层目录
    public boolean createDirectory(FTPClient ftpClient, String remote) throws IOException {
        if (StringUtils.isNotEmpty(remote) && !changeWorkingDirectory(ftpClient, remote)){
            String[] subList = remote.split("/");
            String paths = "";
            for (String sub : subList) {
                paths = paths + "/" + sub;
                if (!isExist(ftpClient, paths)){
                    if (makeDirectory(ftpClient, sub)){
                        changeWorkingDirectory(ftpClient, sub);
                    }else {
                        log.info("创建目录【" + sub + "】失败");
                    }
                }else {
                    changeWorkingDirectory(ftpClient, sub);
                }
            }
        }
        return true;
    }

    //创建文件夹
    private boolean makeDirectory(FTPClient ftpClient, String dir){
        boolean flag = true;
        try {
            flag = ftpClient.makeDirectory(dir);
            if (flag){
                log.info("创建文件夹【" + dir + "】成功");
            }else {
                log.info("创建文件夹【" + dir + "】失败");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return flag;
    }

    public List<String> showPatternFiles(String workspace, String prefix, String suffix){
        List<String> list = new ArrayList<>();
        FTPClient ftpClient = null;
        try {
            ftpClient = connectFtp();
            boolean changeFlag = ftpClient.changeWorkingDirectory(workspace);
            if (!changeFlag){
                throw new IOException("进入目录【" + workspace + "】失败");
            }
            FTPFile[] files = ftpClient.listFiles();
            for (FTPFile ftpFile : files) {
                String fileName = ftpFile.getName();
                if (!".".equals(fileName) && !"..".equals(fileName)){
                    String regex = null;
                    if (StringUtils.isNotEmpty(prefix)){
                        regex = prefix + "*." + suffix;
                    }else {
                        regex = suffix + "$";
                    }
                    Pattern pattern = Pattern.compile(regex);
                    if (pattern.matcher(fileName).find()){
                        list.add(fileName);
                    }
                }
            }
        }catch (IOException e) {
            log.error("获取文件夹失败" + e);
        }finally {
            if (ftpClient != null){
                closeFtp(ftpClient);
            }
        }
        return list;
    }

    //判断ftp文件是否存在
    public boolean isExist(FTPClient ftpClient, String remote) throws IOException {
        FTPFile[] files = ftpClient.listFiles(remote);
        if (files.length > 0){
            return true;
        }
        return false;
    }
}
